package enumerated;//: enumerated/PostOffice.java
// Modeling a post office.

import net.mindview.util.Enums;

import java.util.Iterator;

import static net.mindview.util.Print.print;

class Mail {
  // The NO's lower the probability of random selection:
  enum GeneralDelivery {
    YES, NO1, NO2, NO3, NO4, NO5
  }

  enum Scannability {UNSCANNABLE, YES1, YES2, YES3, YES4}

  enum Readability {ILLEGIBLE, YES1, YES2, YES3, YES4}

  enum Address {INCORRECT, OK1, OK2, OK3, OK4, OK5, OK6}

  enum ReturnAddress {MISSING, OK1, OK2, OK3, OK4, OK5}

  GeneralDelivery generalDelivery;
  Scannability scannability;
  Readability readability;
  Address address;
  ReturnAddress returnAddress;
  static long counter = 0;
  long id = counter++;

  public String toString() {
    return "Mail " + id;
  }

  public String details() {
    return toString() +
        ", General Delivery: " + generalDelivery +
        ", Address Scanability: " + scannability +
        ", Address Readability: " + readability +
        ", Address Address: " + address +
        ", Return address: " + returnAddress;
  }

  // Generate test Mail:
  public static Mail randomMail() {
    Mail m = new Mail();
    m.generalDelivery = Enums.random(GeneralDelivery.class);
    m.scannability = Enums.random(Scannability.class);
    m.readability = Enums.random(Readability.class);
    m.address = Enums.random(Address.class);
    m.returnAddress = Enums.random(ReturnAddress.class);
    return m;
  }

  public static Iterable<Mail> generator(final int count) {
    return new Iterable<Mail>() {
      int n = count;

      public Iterator<Mail> iterator() {
        return new Iterator<Mail>() {
          public boolean hasNext() {
            return n-- > 0;
          }

          public Mail next() {
            return randomMail();
          }

          public void remove() { // Not implemented
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }
}

public class PostOffice {
  enum MailHandler {
    GENERAL_DELIVERY {
      boolean handle(Mail m) {
        switch (m.generalDelivery) {
          case YES:
            print("Using general delivery for " + m);
            return true;
          default:
            return false;
        }
      }
    },
    MACHINE_SCAN {
      boolean handle(Mail m) {
        switch (m.scannability) {
          case UNSCANNABLE:
            return false;
          default:
            switch (m.address) {
              case INCORRECT:
                return false;
              default:
                print("Delivering " + m + " automatically");
                return true;
            }
        }
      }
    },
    VISUAL_INSPECTION {
      boolean handle(Mail m) {
        switch (m.readability) {
          case ILLEGIBLE:
            return false;
          default:
            switch (m.address) {
              case INCORRECT:
                return false;
              default:
                print("Delivering " + m + " normally");
                return true;
            }
        }
      }
    },
    RETURN_TO_SENDER {
      boolean handle(Mail m) {
        switch (m.returnAddress) {
          case MISSING:
            return false;
          default:
            print("Returning " + m + " to sender");
            return true;
        }
      }
    };

    abstract boolean handle(Mail m);
  }

  static void handle(Mail m) {
    for (MailHandler handler : MailHandler.values())
      if (handler.handle(m))
        return;
    print(m + " is a dead letter");
  }

  public static void main(String[] args) {
    for (Mail mail : Mail.generator(10)) {
      print(mail.details());
      handle(mail);
      print("*****");
    }
  }
} /* Output:
Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readability: YES3, Address Address: OK1, Return address: OK1
Delivering Mail 0 normally
*****
Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readability: ILLEGIBLE, Address Address: OK5, Return address: OK1
Delivering Mail 1 automatically
*****
Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readability: YES1, Address Address: OK1, Return address: OK5
Using general delivery for Mail 2
*****
Mail 3, General Delivery: NO4, Address Scanability: YES3, Address Readability: YES1, Address Address: INCORRECT, Return address: OK4
Returning Mail 3 to sender
*****
Mail 4, General Delivery: NO4, Address Scanability: UNSCANNABLE, Address Readability: YES1, Address Address: INCORRECT, Return address: OK2
Returning Mail 4 to sender
*****
Mail 5, General Delivery: NO3, Address Scanability: YES1, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK2
Delivering Mail 5 automatically
*****
Mail 6, General Delivery: YES, Address Scanability: YES4, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK4
Using general delivery for Mail 6
*****
Mail 7, General Delivery: YES, Address Scanability: YES3, Address Readability: YES4, Address Address: OK2, Return address: MISSING
Using general delivery for Mail 7
*****
Mail 8, General Delivery: NO3, Address Scanability: YES1, Address Readability: YES3, Address Address: INCORRECT, Return address: MISSING
Mail 8 is a dead letter
*****
Mail 9, General Delivery: NO1, Address Scanability: UNSCANNABLE, Address Readability: YES2, Address Address: OK1, Return address: OK4
Delivering Mail 9 normally
*****
*///:~
